using System;
using System.Diagnostics;

public abstract class Session : IDisposable
{
    public enum Status
    {
        Idle,
        Connecting,
        Running,
        Disabled,
    };

    private Connection m_connection;
    private Status m_status;

    private ThreadSafeDoubleQueue<NetPacket> m_packets;

    public Session()
    {
        m_packets = new ThreadSafeDoubleQueue<NetPacket>();
    }

    public void Update()
    {
        while (m_packets.Dequeue(out NetPacket pck))
        {
            HandlePacket(pck);
        }
    }

    public void ConnectServer(string host, int port)
    {
        Debug.Assert(m_connection == null || !m_connection.IsActive());
        m_connection = new Connection(this);
        m_connection.Start(host, port);
        m_status = Status.Connecting;
    }

    public void ShutdownSession()
    {
        m_connection.Close();
        m_packets.Clear();
        m_status = Status.Idle;
    }

    public void OnConnected()
    {
        m_status = Status.Running;
    }

    public void OnDisconnected()
    {
        m_status = Status.Disabled;
    }

    public Status GetStatus()
    {
        return m_status;
    }
    public bool IsConnecting()
    {
        return m_status == Status.Connecting;
    }
    public bool IsRunning()
    {
        return m_status == Status.Running;
    }

    public long GetSendDataSize()
    {
        return m_connection.GetOutBuffer().GetSendDataSize();
    }

    public void PushSendPacket(NetPacket pck)
    {
        if (IsRunning())
        {
            m_connection.GetOutBuffer().WritePacket(pck);
            m_connection.TryWrite();
        }
    }

    public void PushSendPacket(NetPacket pck, byte[] data, int offset = 0, int count = -1)
    {
        if (IsRunning())
        {
            m_connection.GetOutBuffer().WritePacket(pck, data, offset, count);
            m_connection.TryWrite();
        }
    }

    public void WritePacket(NetPacket pck, NetPacket data)
    {
        if (IsRunning())
        {
            m_connection.GetOutBuffer().WritePacket(pck, data);
            m_connection.TryWrite();
        }
    }

    public void PushRecvPacket(NetPacket packet)
    {
        if (IsRunning())
        {
            m_packets.Enqueue(packet);
        }
    }

    protected abstract void HandlePacket(NetPacket pck);

    #region IDisposable Support
    private bool disposedValue = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                m_packets = null;
            }
            if (m_connection != null)
            {
                m_connection.Dispose();
                m_connection = null;
            }
            disposedValue = true;
        }
    }

    ~Session()
    {
        Dispose(false);
    }

    void IDisposable.Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    #endregion
}
